
import UIKit
import SnapKit

class AlertAction {
    
    enum Style : Int, @unchecked Sendable {
        case `default` = 0
        case cancel = 1
        case destructive = 2
    }
    
    var title: String!
    var titleColor: UIColor?
    var style: Style!
    var handler: (() -> Void)? = nil
    weak var button: AlertActionButton?

    @discardableResult
    convenience init(title: String, titleColor: UIColor = .main, style: AlertAction.Style = .default,  handler: (() -> Void)? = nil) {
        self.init()
        
        self.title = title
        self.titleColor = titleColor
        self.handler = handler
        self.style = style
    }
    
}


class AlertActionButton: GradientButton {
    var action: AlertAction!
}

class Alert: UIViewController {
    
    struct Constant {
        static let titleColor: UIColor = UIColor.white
        static let titleFont: UIFont = UIFontMediumMake(17)
        static let messageColor: UIColor = UIColor.white
        static let messageFont: UIFont = UIFontMake(14)
    }
    
    enum Style : Int, @unchecked Sendable {
        case actionSheet = 0
        case alert = 1
    }
    
    private var preferredStyle: Style!
    private var message: String?
    private var maskView: UIButton!
    private var contentView: UIView!
    private var titleView: UIView!
    private var actions: [AlertAction] = []
    private var cancelActions: [AlertAction] = []
    private var normalActions: [AlertAction] = []
    private var isContainCancelAction: Bool = false
    
    class func alert(title: String? = nil, message: String? = nil, preferredStyle: Style = .actionSheet) -> Alert {
        let alert = Alert()
        alert.title = title
        alert.message = message
        alert.preferredStyle = preferredStyle
        return alert
    }
    
    @discardableResult
    func addAction(title: String, titleColor: UIColor = .black, style: AlertAction.Style = .default, handler: (() -> Void)? = nil) -> Self {
        let action = AlertAction(title: title, titleColor: titleColor, style: style, handler: handler)
        actions.append(action)
        return self
    }
    
    @discardableResult
    func addAction(action: AlertAction) -> Self {
        actions.append(action)
        return self
    }
    
    func showIn(_ controller: UIViewController) {
        controller.present(self, animated: false, completion: nil)
    }
   
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        modalPresentationStyle = .custom
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .clear
        
        maskView = UIButton(frame: view.bounds).addTo(view)
        maskView.backgroundColor = .black.withAlphaComponent(0)
        
        contentView = UIView().addTo(view)
        contentView.backgroundColor = UIColorMake(0x2E3036)
        
        actions.forEach { action in
            if action.style == .cancel {
                cancelActions.append(action)
            } else {
                normalActions.append(action)
            }
        }
        
        if preferredStyle == .alert {
            alertUI()
        } else {
            actionSheetUI()
        }
    }
    
 
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        if preferredStyle == .alert {
            
            self.contentView.layer.transform = CATransform3DMakeScale(0.7, 0.7, 0.7)
            self.contentView.alpha = 0.7
            UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.8, options: .curveEaseIn) {
                self.contentView.alpha = 1
                self.maskView.backgroundColor = .black.withAlphaComponent(0.5)
                self.contentView.layer.transform = CATransform3DMakeScale(1, 1, 1)
            }
        } else {
            
            UIView.animate(withDuration: 0.25) {
                self.maskView.backgroundColor = .black.withAlphaComponent(0.5)
                self.contentView.y = self.view.height - self.contentView.height
            }
        }
        
    }
    
    
}

extension Alert {
    
    func alertUI() {
        
        let titleView = UIView().addTo(contentView)
        
        let contentW = view.width - 100
        let leftRightMargin: CGFloat = 20
        
        if let title = title, !title.isEmpty {
            let titleLabel = UILabel(text: self.title, font: Constant.titleFont, textColor: Constant.titleColor, textAlignment: .center).addTo(titleView)
            titleLabel.numberOfLines = 0
            titleLabel.snp.makeConstraints { make in
                make.width.lessThanOrEqualTo(contentW - leftRightMargin * 2)
                make.top.equalTo(20)
                make.centerX.equalToSuperview()
            }
            titleView.snp.makeConstraints { make in
                make.top.right.left.equalToSuperview();
                make.bottom.equalTo(titleLabel.snp.bottom);
            }
        } else {
            titleView.snp.makeConstraints { make in
                make.top.equalTo(20)
                make.right.left.equalToSuperview();
                make.height.equalTo(0)
            }
        }
        
        var messageLabel: UILabel?
        
        if let message = message, !message.isEmpty {
            messageLabel = UILabel(text: self.message, font: Constant.messageFont, textColor: Constant.messageColor, textAlignment: .center).addTo(titleView)
            messageLabel!.numberOfLines = 0
            messageLabel!.snp.makeConstraints { make in
                make.width.lessThanOrEqualTo(contentW - leftRightMargin * 2)
                make.top.equalTo(titleView.snp.bottom).offset(16);
                make.centerX.equalToSuperview()
            }
        }
        
        let buttonMargin = 12
        let buttonContentViewH = actions.count * 40 + (actions.count - 1) * buttonMargin
        let buttonContentView = UIView().addTo(contentView)
        buttonContentView.snp.makeConstraints { make in
            make.width.equalTo(contentW - leftRightMargin * 2)
            make.centerX.equalToSuperview()
            make.height.equalTo(buttonContentViewH)
            if let messageLabel = messageLabel {
                make.top.equalTo(messageLabel.snp.bottom).offset(20)
            } else {
                make.top.equalTo(titleView.snp.bottom).offset(20)
            }
        }
        
        for (index, action) in actions.enumerated() {
            
            var button: AlertActionButton!
            
            if (action.style == .destructive) {
                button = AlertActionButton(type: .system, title: action.title, font: UIFontMake(16), textColor: .red, target: self, action: #selector(didClickButton(_:)))
                button.backgroundColor = UIColorMake(0xEDEFF5)
            } else if (action.style == .cancel) {
                button = AlertActionButton(type: .system, title: action.title, font: UIFontMake(16), textColor: UIColorMake(0x555555), target: self, action: #selector(didClickButton(_:)))
                button.backgroundColor = UIColorMake(0xEDEFF5)
            } else {
                button = AlertActionButton(type: .system, title: action.title, font: UIFontMake(16), textColor: .white, target: self, action: #selector(didClickButton(_:)))
                button.colors = [UIColorMake(0x05D4FC), UIColorMake(0xBE0DEF), UIColorMake(0xF202D3)]
                button.locations = [0, 0.66, 1]
                button.setStartPoint(CGPoint(x: 0, y: 0.5), endPoint: CGPointMake(1, 0.5))
                button.isGradientBorder = false
                button.layer.cornerRadius = 5
                button.layer.masksToBounds = true
            }
            
            button.addCorner(radius: 10)
            button.action = action
            button.addTo(buttonContentView)
            button.snp.makeConstraints { make in
                make.top.equalTo(index * (40 + buttonMargin))
                make.height.equalTo(40)
                make.centerX.equalToSuperview()
                make.width.equalToSuperview()
            }
            
            action.button = button
        }
        
        view.layoutIfNeeded()
        
        contentView.frame = CGRectMake(0, view.height, contentW, CGRectGetMaxY(buttonContentView.frame) + 20)
        contentView.center = view.center
        contentView.addCorner(radius: 16)
    }
    
    
    @objc func didClickButton(_ button: AlertActionButton) {
        
        UIView.animate(withDuration: 0.25) {
//            self.contentView.alpha = 0
            self.maskView.backgroundColor = .black.withAlphaComponent(0.5)
        } completion: { finishi in
            self.dismiss(animated: false) {
                let action = button.action
                action?.handler?()
            }
        }
    }
}


extension Alert {

    func actionSheetUI() {
        
        maskView.addTarget(self, action: #selector(dismissController), for: .touchUpInside)
        
        let contentW = view.width
        let leftRightMargin: CGFloat = 30
        titleView = UIView().addTo(contentView)
        
        if let title = title, !title.isEmpty {
            let titleLabel = UILabel(text: title, font: Constant.titleFont, textColor: Constant.titleColor).addTo(titleView)
            titleLabel.numberOfLines = 0
            titleLabel.snp.makeConstraints { make in
                make.width.lessThanOrEqualTo(contentW - leftRightMargin)
                make.top.equalTo(20)
                make.centerX.equalToSuperview()
            }
        }
        
        if let message = message, !message.isEmpty {

            let titleLabel = titleView.subviews.first

            let messageLabel = UILabel(text: self.message, font: Constant.messageFont, textColor: Constant.messageColor, textAlignment: .center).addTo(titleView)
            messageLabel.numberOfLines = 0
            messageLabel.snp.makeConstraints { make in
                make.width.lessThanOrEqualTo(contentW - leftRightMargin)
                make.centerX.equalToSuperview()
                if (titleLabel != nil) {
                    make.top.equalTo(titleLabel!.snp.bottom).offset(16);
                } else {
                    make.top.equalTo(20)
                }
            }
        }
   
        if let lastView = titleView.subviews.last {
            
            lastView.snp.makeConstraints { make in
                make.bottom.equalToSuperview().offset(-16)
            }

            titleView.snp.makeConstraints { make in
                make.top.right.left.equalToSuperview()
            }
            
        } else {
            titleView.isHidden = true
            titleView.snp.makeConstraints { make in
                make.top.right.left.equalToSuperview()
                make.height.equalTo(0)
            }
        }
        
        view.setNeedsLayout()
        view.layoutIfNeeded()
        
        
        let tableView = UITableView(frame: .zero, style: .plain).addTo(contentView)
        tableView.contentInsetAdjustmentBehavior = .never
        tableView.dataSource = self
        tableView.delegate = self
        tableView.rowHeight = 50
        tableView.separatorStyle = .none
        tableView.isScrollEnabled = false
        tableView.register(AlertActionCell.self, forCellReuseIdentifier: "AlertActionCell")
        tableView.register(AlertCancelActionCell.self, forCellReuseIdentifier: "AlertCancelActionCell")
        tableView.snp.makeConstraints { make in
            make.top.equalTo(titleView.snp.bottom)
            make.left.right.bottom.equalToSuperview()
        }
        
        let tableViewH: CGFloat = tableView.rowHeight * CGFloat(actions.count) + CGFloat(cancelActions.count) * 10.0 + tabBarSafeBottomMargin + titleView.height
        contentView.frame = CGRectMake(0, view.height, view.width, tableViewH)
        contentView.addRoundingCorners([.topLeft, .topRight], radius: 12)
    }
    
    @objc func dismissController() {
        dismiss()
    }
    
    func dismiss(completion: (() -> Void)? = nil) {
        
        UIView.animate(withDuration: 0.25) {
            self.maskView.backgroundColor = .black.withAlphaComponent(0)
            self.contentView.y = self.view.height
        } completion: { finish in
            self.dismiss(animated: false, completion: completion)
        }
    }
}


protocol AlertActionCellProtocol {
    var titleLabel: UILabel! { get set }
    var lineView: UIView! { get set }
    var action: AlertAction! { get set }
}

class AlertCancelActionCell: UITableViewCell, AlertActionCellProtocol {
    
    var titleLabel: UILabel!
    var lineView: UIView!

    var action: AlertAction! {
        didSet {
            titleLabel.text = action.title
            titleLabel.textColor = action.titleColor
        }
    }
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        titleLabel = UILabel(font: UIFontMake(15), textColor: .black, textAlignment: .center).addTo(contentView)
        titleLabel.snp.makeConstraints { make in
            make.top.centerX.equalToSuperview()
            make.bottom.equalToSuperview().offset(-tabBarSafeBottomMargin)
        }
        
        lineView = UIView().addTo(contentView)
        lineView.backgroundColor = AppStyle.color.cellGrayBackground
        lineView.snp.makeConstraints { make in
            make.left.right.top.equalToSuperview()
            make.height.equalTo(0.7)
        }
        
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}



class AlertActionCell: UITableViewCell, AlertActionCellProtocol {
    
    var titleLabel: UILabel!
    var lineView: UIView!
    var action: AlertAction! {
        didSet {
            titleLabel.text = action.title
            if action.style == AlertAction.Style.destructive {
                titleLabel.textColor = .red
            } else {
                titleLabel.textColor = .black
            }
        }
    }
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        titleLabel = UILabel(font: UIFontMake(15), textColor: .black, textAlignment: .center).addTo(contentView)
        titleLabel.snp.makeConstraints { make in
            make.center.equalToSuperview()
        }
        
        lineView = UIView().addTo(contentView)
        lineView.backgroundColor = AppStyle.color.cellGrayBackground
        lineView.snp.makeConstraints { make in
            make.left.right.top.equalToSuperview()
            make.height.equalTo(0.7)
        }
        
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}


extension Alert: UITableViewDelegate, UITableViewDataSource {
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if (section == 0) {
            return normalActions.count
        }
        return cancelActions.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.section == 1 {
            let cancelActionCell = tableView.dequeueReusableCell(withIdentifier: "AlertCancelActionCell", for: indexPath) as! AlertCancelActionCell
            cancelActionCell.action = cancelActions[indexPath.row]
            return cancelActionCell
        }
        
        let actionCell = tableView.dequeueReusableCell(withIdentifier: "AlertActionCell", for: indexPath) as! AlertActionCell
        actionCell.action = normalActions[indexPath.row]
        actionCell.lineView.isHidden = indexPath.row == 0 && titleView.isHidden
        return actionCell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        
        let cell: AlertActionCellProtocol = tableView.cellForRow(at: indexPath) as! AlertActionCellProtocol
        
        dismiss {
            let action = cell.action
            action?.handler?()
        }
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if indexPath.section == 1 {
            return tableView.rowHeight + tabBarSafeBottomMargin
        }
        return tableView.rowHeight
    }
    
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 0.0
    }
    
    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        let footerView = UIView()
        footerView.backgroundColor = UIColorMake(0xEEEEEE)
        return footerView
    }
    
    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return section == 0 ? 10.0 : 0.0
    }
    
    
}

